var vertStr = `
attribute vec3 vertex;
uniform vec3 eye,ray00,ray01,ray10,ray11;
varying vec3 initialRay;
void main(){
    vec2 percent=vertex.xy*.5+.5;
    initialRay=mix(mix(ray00,ray01,percent.y),mix(ray10,ray11,percent.y),percent.x);
    gl_Position=vec4(vertex,1.);
}
`;

var fragStr = `

precision highp float;
uniform vec3 eye;
varying vec3 initialRay;
uniform float textureWeight;
uniform float timeSinceStart;
uniform sampler2D texture;
uniform float glossiness;
vec3 roomCubeMin=vec3(-1.,-1.,-1.);
vec3 roomCubeMax=vec3(1.,1.,1.);
uniform vec3 light;
uniform vec3 cubeMin0;
uniform vec3 cubeMax0;

uniform vec3 cubeMin1;
uniform vec3 cubeMax1;

uniform vec3 cubeMin2;
uniform vec3 cubeMax2;

uniform vec3 cubeMin3;
uniform vec3 cubeMax3;

uniform vec3 cubeMin4;
uniform vec3 cubeMax4;

uniform vec3 cubeMin5;
uniform vec3 cubeMax5;

uniform vec3 cubeMin6;
uniform vec3 cubeMax6;

uniform vec3 cubeMin7;
uniform vec3 cubeMax7;

uniform vec3 cubeMin8;
uniform vec3 cubeMax8;

uniform vec3 cubeMin9;
uniform vec3 cubeMax9;

uniform vec3 cubeMin10;
uniform vec3 cubeMax10;

uniform vec3 cubeMin11;
uniform vec3 cubeMax11;

uniform vec3 cubeMin12;
uniform vec3 cubeMax12;

uniform vec3 sphereCenter13;
uniform float sphereRadius13;

vec2 intersectCube(vec3 origin,vec3 ray,vec3 cubeMin,vec3 cubeMax){
    vec3 tMin=(cubeMin-origin)/ray;
    vec3 tMax=(cubeMax-origin)/ray;
    vec3 t1=min(tMin,tMax);
    vec3 t2=max(tMin,tMax);
    float tNear=max(max(t1.x,t1.y),t1.z);
    float tFar=min(min(t2.x,t2.y),t2.z);
    return vec2(tNear,tFar);
}

vec3 normalForCube(vec3 hit,vec3 cubeMin,vec3 cubeMax)
{
    if(hit.x<cubeMin.x+.0001)return vec3(-1.,0.,0.);
    else if(hit.x>cubeMax.x-.0001)return vec3(1.,0.,0.);
    else if(hit.y<cubeMin.y+.0001)return vec3(0.,-1.,0.);
    else if(hit.y>cubeMax.y-.0001)return vec3(0.,1.,0.);
    else if(hit.z<cubeMin.z+.0001)return vec3(0.,0.,-1.);
    else return vec3(0.,0.,1.);
}

float intersectSphere(vec3 origin,vec3 ray,vec3 sphereCenter,float sphereRadius){
    vec3 toSphere=origin-sphereCenter;
    float a=dot(ray,ray);
    float b=2.*dot(toSphere,ray);
    float c=dot(toSphere,toSphere)-sphereRadius*sphereRadius;
    float discriminant=b*b-4.*a*c;
    if(discriminant>0.){
        float t=(-b-sqrt(discriminant))/(2.*a);
        if(t>0.)return t;
    }
    return 10000.;
}

vec3 normalForSphere(vec3 hit,vec3 sphereCenter,float sphereRadius){
    return(hit-sphereCenter)/sphereRadius;
}

float random(vec3 scale,float seed){
    return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);
}

vec3 cosineWeightedDirection(float seed,vec3 normal){
    float u=random(vec3(12.9898,78.233,151.7182),seed);
    float v=random(vec3(63.7264,10.873,623.6736),seed);
    float r=sqrt(u);
    float angle=6.283185307179586*v;
    // compute basis from normal
    vec3 sdir,tdir;
    if(abs(normal.x)<.5){
        sdir=cross(normal,vec3(1,0,0));
    }else{
        sdir=cross(normal,vec3(0,1,0));
    }
    tdir=cross(normal,sdir);
    return r*cos(angle)*sdir+r*sin(angle)*tdir+sqrt(1.-u)*normal;
}

vec3 uniformlyRandomDirection(float seed){
    float u=random(vec3(12.9898,78.233,151.7182),seed);
    float v=random(vec3(63.7264,10.873,623.6736),seed);
    float z=1.-2.*u;
    float r=sqrt(1.-z*z);
    float angle=6.283185307179586*v;
    return vec3(r*cos(angle),r*sin(angle),z);
}

vec3 uniformlyRandomVector(float seed){
    return uniformlyRandomDirection(seed)*sqrt(random(vec3(36.7539,50.3658,306.2759),seed));
}

float shadow(vec3 origin,vec3 ray){
    vec2 tCube0=intersectCube(origin,ray,cubeMin0,cubeMax0);
    if(tCube0.x>0.&&tCube0.x<1.&&tCube0.x<tCube0.y)return 0.;
    vec2 tCube1=intersectCube(origin,ray,cubeMin1,cubeMax1);
    if(tCube1.x>0.&&tCube1.x<1.&&tCube1.x<tCube1.y)return 0.;
    vec2 tCube2=intersectCube(origin,ray,cubeMin2,cubeMax2);
    if(tCube2.x>0.&&tCube2.x<1.&&tCube2.x<tCube2.y)return 0.;
    vec2 tCube3=intersectCube(origin,ray,cubeMin3,cubeMax3);
    if(tCube3.x>0.&&tCube3.x<1.&&tCube3.x<tCube3.y)return 0.;
    vec2 tCube4=intersectCube(origin,ray,cubeMin4,cubeMax4);
    if(tCube4.x>0.&&tCube4.x<1.&&tCube4.x<tCube4.y)return 0.;
    vec2 tCube5=intersectCube(origin,ray,cubeMin5,cubeMax5);
    if(tCube5.x>0.&&tCube5.x<1.&&tCube5.x<tCube5.y)return 0.;
    vec2 tCube6=intersectCube(origin,ray,cubeMin6,cubeMax6);
    if(tCube6.x>0.&&tCube6.x<1.&&tCube6.x<tCube6.y)return 0.;
    vec2 tCube7=intersectCube(origin,ray,cubeMin7,cubeMax7);
    if(tCube7.x>0.&&tCube7.x<1.&&tCube7.x<tCube7.y)return 0.;
    vec2 tCube8=intersectCube(origin,ray,cubeMin8,cubeMax8);
    if(tCube8.x>0.&&tCube8.x<1.&&tCube8.x<tCube8.y)return 0.;
    vec2 tCube9=intersectCube(origin,ray,cubeMin9,cubeMax9);
    if(tCube9.x>0.&&tCube9.x<1.&&tCube9.x<tCube9.y)return 0.;
    vec2 tCube10=intersectCube(origin,ray,cubeMin10,cubeMax10);
    if(tCube10.x>0.&&tCube10.x<1.&&tCube10.x<tCube10.y)return 0.;
    vec2 tCube11=intersectCube(origin,ray,cubeMin11,cubeMax11);
    if(tCube11.x>0.&&tCube11.x<1.&&tCube11.x<tCube11.y)return 0.;
    vec2 tCube12=intersectCube(origin,ray,cubeMin12,cubeMax12);
    if(tCube12.x>0.&&tCube12.x<1.&&tCube12.x<tCube12.y)return 0.;
    float tSphere13=intersectSphere(origin,ray,sphereCenter13,sphereRadius13);
    if(tSphere13<1.)return 0.;
    return 1.;
}
vec3 calculateColor(vec3 origin,vec3 ray,vec3 light){
    vec3 colorMask=vec3(1.);
    vec3 accumulatedColor=vec3(0.);
    // 光线跟踪循环
    for(int bounce=0;bounce<5;bounce++){
        // 和所有的东西都计算一下交点
        vec2 tRoom=intersectCube(origin,ray,roomCubeMin,roomCubeMax);
        vec2 tCube0=intersectCube(origin,ray,cubeMin0,cubeMax0);
        vec2 tCube1=intersectCube(origin,ray,cubeMin1,cubeMax1);
        vec2 tCube2=intersectCube(origin,ray,cubeMin2,cubeMax2);
        vec2 tCube3=intersectCube(origin,ray,cubeMin3,cubeMax3);
        vec2 tCube4=intersectCube(origin,ray,cubeMin4,cubeMax4);
        vec2 tCube5=intersectCube(origin,ray,cubeMin5,cubeMax5);
        vec2 tCube6=intersectCube(origin,ray,cubeMin6,cubeMax6);
        vec2 tCube7=intersectCube(origin,ray,cubeMin7,cubeMax7);
        vec2 tCube8=intersectCube(origin,ray,cubeMin8,cubeMax8);
        vec2 tCube9=intersectCube(origin,ray,cubeMin9,cubeMax9);
        vec2 tCube10=intersectCube(origin,ray,cubeMin10,cubeMax10);
        vec2 tCube11=intersectCube(origin,ray,cubeMin11,cubeMax11);
        vec2 tCube12=intersectCube(origin,ray,cubeMin12,cubeMax12);
        float tSphere13=intersectSphere(origin,ray,sphereCenter13,sphereRadius13);
        float t=10000.;
        if(tRoom.x<tRoom.y) t=tRoom.y;
        // 找到最近的交点
        if(tCube0.x>0.&&tCube0.x<tCube0.y&&tCube0.x<t) t=tCube0.x;
        if(tCube1.x>0.&&tCube1.x<tCube1.y&&tCube1.x<t)t=tCube1.x;
        if(tCube2.x>0.&&tCube2.x<tCube2.y&&tCube2.x<t)t=tCube2.x;
        if(tCube3.x>0.&&tCube3.x<tCube3.y&&tCube3.x<t)t=tCube3.x;
        if(tCube4.x>0.&&tCube4.x<tCube4.y&&tCube4.x<t)t=tCube4.x;
        if(tCube5.x>0.&&tCube5.x<tCube5.y&&tCube5.x<t)t=tCube5.x;
        if(tCube6.x>0.&&tCube6.x<tCube6.y&&tCube6.x<t)t=tCube6.x;
        if(tCube7.x>0.&&tCube7.x<tCube7.y&&tCube7.x<t)t=tCube7.x;
        if(tCube8.x>0.&&tCube8.x<tCube8.y&&tCube8.x<t)t=tCube8.x;
        if(tCube9.x>0.&&tCube9.x<tCube9.y&&tCube9.x<t)t=tCube9.x;
        if(tCube10.x>0.&&tCube10.x<tCube10.y&&tCube10.x<t)t=tCube10.x;
        if(tCube11.x>0.&&tCube11.x<tCube11.y&&tCube11.x<t)t=tCube11.x;
        if(tCube12.x>0.&&tCube12.x<tCube12.y&&tCube12.x<t)t=tCube12.x;
        if(tSphere13<t)t=tSphere13;
        vec3 hit=origin+ray*t;
        vec3 surfaceColor=vec3(.75);
        float specularHighlight=0.;
        vec3 normal;
        // 计算法线并更改墙的颜色
        if(t==tRoom.y){
            normal=-normalForCube(hit,roomCubeMin,roomCubeMax);
            
            if(hit.x<-.9999)surfaceColor=vec3(1.,.3,.1);// red
            else if(hit.x>.9999)surfaceColor=vec3(.3,1.,.1);// green
            ray = cosineWeightedDirection(timeSinceStart + float(bounce), normal);
        }else if(t==10000.){
            break;
        }else{
            if(false);// hack to discard the first 'else' in 'else if'
            // 交点的信息
            else if(t==tCube0.x&&tCube0.x<tCube0.y)normal=normalForCube(hit,cubeMin0,cubeMax0);
			else if(t==tCube1.x&&tCube1.x<tCube1.y)normal=normalForCube(hit,cubeMin1,cubeMax1);
			else if(t==tCube2.x&&tCube2.x<tCube2.y)normal=normalForCube(hit,cubeMin2,cubeMax2);
			else if(t==tCube3.x&&tCube3.x<tCube3.y)normal=normalForCube(hit,cubeMin3,cubeMax3);
			else if(t==tCube4.x&&tCube4.x<tCube4.y)normal=normalForCube(hit,cubeMin4,cubeMax4);
			else if(t==tCube5.x&&tCube5.x<tCube5.y)normal=normalForCube(hit,cubeMin5,cubeMax5);
			else if(t==tCube6.x&&tCube6.x<tCube6.y)normal=normalForCube(hit,cubeMin6,cubeMax6);
			else if(t==tCube7.x&&tCube7.x<tCube7.y)normal=normalForCube(hit,cubeMin7,cubeMax7);
			else if(t==tCube8.x&&tCube8.x<tCube8.y)normal=normalForCube(hit,cubeMin8,cubeMax8);
			else if(t==tCube9.x&&tCube9.x<tCube9.y)normal=normalForCube(hit,cubeMin9,cubeMax9);
			else if(t==tCube10.x&&tCube10.x<tCube10.y)normal=normalForCube(hit,cubeMin10,cubeMax10);
			else if(t==tCube11.x&&tCube11.x<tCube11.y)normal=normalForCube(hit,cubeMin11,cubeMax11);
			else if(t==tCube12.x&&tCube12.x<tCube12.y)normal=normalForCube(hit,cubeMin12,cubeMax12);
			else if(t==tSphere13)normal=normalForSphere(hit,sphereCenter13,sphereRadius13);
			ray=cosineWeightedDirection(timeSinceStart+float(bounce),normal);
        }
        
        // 计算漫反射的光照贡献
        vec3 toLight=light-hit;
        float diffuse=max(0.,dot(normalize(toLight),normal));
        // 给光线后面接上阴影
        float shadowIntensity=shadow(hit+normal*.0001,toLight);
        // 反射光
        colorMask*=surfaceColor;
        accumulatedColor+=colorMask*(.6*diffuse*shadowIntensity);
        accumulatedColor+=colorMask*specularHighlight*shadowIntensity;
        // 把交点当作起点，进行下一次更新
        origin=hit;
    }
    return accumulatedColor;
}

void main(){
    // vec3 newLight=light+uniformlyRandomVector(timeSinceStart-53.)*.1;
    vec3 newLight= vec3(0.6, 0.6 ,0.6);
    vec3 texture=texture2D(texture,gl_FragCoord.xy/512.).rgb;
    gl_FragColor=vec4(mix(calculateColor(eye,initialRay,newLight),texture,textureWeight),1.);
}
`;